package yxy.cherry.battle.module.affix;

import yxy.apple.util.ReflectionUtility;
import yxy.cherry.battle.Fighter;
import yxy.cherry.battle.module.affix.condition.AffixCondition;
import yxy.cherry.battle.module.affix.condition.AffixconditionType;
import yxy.cherry.battle.module.selector.TargetSelector;
import yxy.cherry.battle.module.selector.TargetSelectorFactory;
import yxy.cherry.data.DataCenter;
import yxy.cherry.data.bean.skill;
import yxy.cherry.data.bean.skillgroup;

import java.util.*;

public class AffixFactory {
	static private AffixFactory instance;

	public static AffixFactory getInstance() {
		if (instance == null) {
			instance = new AffixFactory();
			instance.init();
		}
		return instance;
	}

	private AffixFactory() {
	}

	private Map<SkillTypeEnum, Class<?>> skillClassMap = new HashMap<>();
	private Map<BuffTypeEnum, Class<?>> buffClassMap = new HashMap<>();
	private Map<Integer, Class<?>> affixConditionMap = new HashMap<>();

	private void init() {
		Set<Class<? extends Skill>> skillClassSet = ReflectionUtility.getSubTypesOf("yxy.cherry.battle.module.affix", Skill.class);
		for (Class<?> clazz : skillClassSet) {
			SkillTypeEnum type = clazz.getAnnotation(SkillType.class).Type();
			skillClassMap.put(type, clazz);
		}

		Set<Class<? extends Buff>> buffClassSet = ReflectionUtility.getSubTypesOf("yxy.cherry.battle.module.affix", Buff.class);
		for (Class<?> clazz : buffClassSet) {
			BuffTypeEnum type = clazz.getAnnotation(BuffType.class).Type();
			buffClassMap.put(type, clazz);
		}

		Set<Class<? extends AffixCondition>> affixConditionSet = ReflectionUtility.getSubTypesOf("yxy.cherry.battle.module.affix", AffixCondition.class);
		for (Class<?> clazz : affixConditionSet) {
			int type = clazz.getAnnotation(AffixconditionType.class).Type();
			affixConditionMap.put(type, clazz);
		}
	}

	public Skill getSkill(SkillTypeEnum type, Fighter actor, skill skilldata, int level) {
		try {
			int probability = skilldata.getProbability() + skilldata.getProbabilityup() * level;
			int[] params = new int[skilldata.getParam().length];
			for (int i = 0; i < params.length; i++) {
				params[i] = skilldata.getParam()[i] + skilldata.getPromote()[i] * level;
			}
			return (Skill) skillClassMap.get(type).getDeclaredConstructor(Fighter.class, skill.class, int.class, int[].class).newInstance(actor, skilldata,
					probability, params);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public Buff getBuff(BuffTypeEnum type, Fighter source, Fighter target, skill skilldata, int... params) {
		try {
			return (Buff) buffClassMap.get(type).getDeclaredConstructor(Fighter.class, Fighter.class, skill.class, int[].class).newInstance(source, target,
					skilldata, params);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public AffixCondition getAffixCondition(int type, int param) {
		try {
			if(type == 0){
				return null;
			}
			return (AffixCondition) affixConditionMap.get(type).getDeclaredConstructor(int.class).newInstance(param);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	static public enum SkillTypeEnum {
		BUFF(1), //
		物攻(2), //
		法攻(3), //
		治疗(4), //
		复活(5), //
		追攻(6), //
		反击(7), //
		援护(8), //
		致死(9), //
		驱散(10), //
		受伤反弹(11), //
		伤害治疗(12), //
		伤害绝对值(13), //
		增伤(14), //
		增伤敌阵亡(15), //
		增伤靠数值(16), //
		增伤靠减血(17), //
		减伤(18), //
		减伤靠减血(19), //
		怒气(20), //
		怒气抢夺(21), //
		无视防御(22), //
		生命汲取(24),//生命汲取
		伤害均摊(25),//伤害分担
		偷取属性(28),//偷取属性
		吸血靠减血(29),//偷取属性
		强化追攻(30),
		;

		private int number;

		private SkillTypeEnum(int number) {
			this.number = number;
		}
	}

	static public enum BuffTypeEnum {
		中毒(51), //
		灼烧(52), //
		回春(53), //
		眩晕(54), //
		麻痹(55), //
		沉默(56), //
		混乱(57), //
		嘲讽(58), //
		增伤(59), //
		减伤(60), //
		免死(61), //免死盾
		护盾(62), //属性盾
		减疗(63), //
		属性加(64), //
		属性减(65), //
		属性加固定值(66), //
		属性减固定值(67), //
		虚弱(68),//虚弱
		破甲(69),//破甲
		压制(71),//压制
		集智(72),//集智
		固守(73),//固守
		谋略(74),//谋略
		奇谋(75),//感伤
		盛怒(76),//盛怒
		属性加靠失血(77),
		属性加靠减血(78),
		属性加固定值靠减血(79),
		属性加固定值靠失血(80),
		狱火(81),
		神雷(82),
		解除免死(83),
		全体属性衰减(84)
		;

		private int number;

		private BuffTypeEnum(int number) {
			this.number = number;
		}
	}

	public Collection<Skill> createAffix(Fighter actor, int skillGroupId, int level, int stage) {
		skillgroup _skillgroup = DataCenter.getData(skillGroupId, skillgroup.class);
		if (_skillgroup == null || _skillgroup.getCondition() > stage) {
			return new ArrayList<>();
		}

		return createAffix(actor, _skillgroup, level);
	}

	public Collection<Skill> createAffix(Fighter actor, String skillCode, int level) {
		skillgroup _skillgroup = DataCenter.getData(skillCode, skillgroup.class);
		return createAffix(actor, _skillgroup, level);
	}

	private Collection<Skill> createAffix(Fighter actor, skillgroup _skillgroup, int level) {
		ArrayList<Skill> skillList = new ArrayList<>();
		for (int i = 0; i < _skillgroup.getSkillid().length; i++) {
			try {
				int skillId = _skillgroup.getSkillid()[i];
				skill skilldata = DataCenter.getData(skillId, skill.class);
				if (skilldata == null) {
					continue;
				}
				Skill skill = getSkill(//
						SkillTypeEnum.valueOf(skilldata.getType()), //
						actor, //
						skilldata, //
						level//
				);
				if (skill == null) {
					continue;
				}
				// 目标选择器
				TargetSelector targetSelector = TargetSelectorFactory.getInstance().getTargetSelector(skilldata.getSkillobject());
				skill.setTargetSelector(targetSelector);

				// 条件判断器
				for (int j = 0; j < skilldata.getCondition().length; j++) {
					AffixCondition condition = getAffixCondition(skilldata.getCondition()[j], skilldata.getConparam()[j]);
					if (condition != null) {
						skill.addAffixCondition(condition);
					}
				}
				skillList.add(skill);
			} catch (Exception e) {
				e.printStackTrace();
				continue;
			}
		}
		return skillList;
	}
}
